home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume18 / mush6.4 / part16 < prev    next >
Encoding:
Internet Message Format  |  1989-03-12  |  48.5 KB

  1. Subject:  v18i038:  Mail user's shell version 6.4, Part16/19
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Dan Heller <island!argv@sun.com>
  7. Posting-number: Volume 18, Issue 38
  8. Archive-name: mush6.4/part16
  9.  
  10.  
  11.  
  12. #! /bin/sh
  13. # This is a shell archive.  Remove anything before this line, then unpack
  14. # it by saving it into a file and typing "sh file".  To overwrite existing
  15. # files, type "sh file -c".  You can also feed this as standard input via
  16. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  17. # will see the following message at the end:
  18. #        "End of archive 16 (of 19)."
  19. # Contents:  mail.c
  20. # Wrapped by rsalz@papaya.bbn.com on Mon Mar 13 19:25:22 1989
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. if test -f 'mail.c' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'mail.c'\"
  24. else
  25. echo shar: Extracting \"'mail.c'\" \(46580 characters\)
  26. sed "s/^X//" >'mail.c' <<'END_OF_FILE'
  27. X/* @(#)mail.c     (c) copyright 1986 (Dan Heller) */
  28. X
  29. X#include "mush.h"
  30. X
  31. X/*
  32. X * mail.c --
  33. X *    do_mail()     invoked from within mail.  see function for description.
  34. X *    abort_mail()    suntools specific: resets panel items and so forth.
  35. X *    start_file()      creates the editing file and reset signal catching.
  36. X *    mail_someone()    called from do_mail() or from the shell.
  37. X *    add_to_letter()    adds the next line to letter --determine ~ escapes.
  38. X *    finish_up_letter()  prompts for Cc:, verifies user really wants to send
  39. X *    send_it()        invokes mailer, sends to record file, expands aliases,
  40. X *            adds own_hdrs.
  41. X *    rm_edfile()    signals are directed here. remove letter, longjmp
  42. X *
  43. X * The flow of control in this file is NOT obvious to allow for both text
  44. X * and suntools _event driven_ attributes.  In text, the flow is far more
  45. X * obvious because it is sequential. In suntools, each function is called
  46. X * from outside this module.  Keystrokes are interpreted individually and
  47. X * queued up in "rite.c".  select.c calls add_to_letter when a \n is entered
  48. X * passing the string stored in rite.c.  If you're trying to follow the flow
  49. X * of control for suntools, keep the event drivers in mind and follow select.c
  50. X * and rite.c
  51. X */
  52. X#define TO_FIELD    1
  53. X#define SUBJECT        2
  54. X#define CC_FIELD    3
  55. X#define BC_FIELD    4
  56. X
  57. Xstatic char Subject[BUFSIZ],To[HDRSIZ],Cc[HDRSIZ],Bcc[HDRSIZ],in_reply_to[256];
  58. Xstatic int killme;
  59. Xstatic u_long flags;
  60. Xstatic SIGRET (*oldterm)(), (*oldint)(), (*oldquit)();
  61. Xstatic void send_it();
  62. Xstatic jmp_buf cntrl_c_buf;
  63. XFILE *ed_fp;
  64. Xchar *edfile;
  65. X
  66. X/* argc, and argv could be null if coming from compose */
  67. Xdo_mail(n, argv, list)
  68. Xregister int n;   /* no need for "argc", so use the space for a variable */
  69. Xregister char **argv, *list;
  70. X{
  71. X    char firstchar = (argv)? **argv: 'm';
  72. X    char *to = NULL, *cc = NULL, *addcc = NULL, *bcc = NULL, *subj = NULL;
  73. X    char *route = NULL;
  74. X    char inc_list[MAXMSGS_BITS], buf[HDRSIZ];
  75. X    u_long flgs = 0;
  76. X
  77. X    if (ison(glob_flags, IS_GETTING)) {
  78. X    print("You must finish the letter you are editing first.\n");
  79. X    return -1;
  80. X    }
  81. X    if (ison(glob_flags, DO_PIPE)) {
  82. X    print("You can't pipe through the mail command.\n");
  83. X    return -1;
  84. X    }
  85. X    turnon(flgs, NO_IGNORE); /* if we include a message, include all hdrs */
  86. X    clear_msg_list(inc_list);
  87. X
  88. X    if (do_set(set_options, "autoedit"))
  89. X    turnon(flgs, EDIT);
  90. X#ifdef VERBOSE_ARG
  91. X    if (do_set(set_options, "verbose"))
  92. X    turnon(flgs, VERBOSE);
  93. X#endif /* VERBOSE_ARG */
  94. X    if (do_set(set_options, "autosign"))
  95. X    turnon(flgs, SIGN);
  96. X    /* If piped to mail, include the messages piped */
  97. X    if (ison(glob_flags, IS_PIPE) ||
  98. X    (lower(firstchar) == 'r' && do_set(set_options, "autoinclude"))) {
  99. X    turnon(flgs, INCLUDE);
  100. X    bitput(list, inc_list, msg_cnt, =);
  101. X    }
  102. X    while (argv && *argv && *++argv && **argv == '-') {
  103. X    n = 1;
  104. X    while (n && argv[0][n])
  105. X        switch (argv[0][n]) {
  106. X#ifdef VERBOSE_ARG
  107. X        case 'v': turnon(flgs, VERBOSE); n++; break;
  108. X#endif /* VERBOSE_ARG */
  109. X        case 'e': turnon(flgs, EDIT); n++;
  110. X        when 'F': turnon(flgs, DO_FORTUNE); n++;
  111. X        when 'b':
  112. X            if (argv[1]) {
  113. X            n = 0, bcc = *++argv;
  114. X            fix_up_addr(bcc);
  115. X            } else {
  116. X            print("Must specify blind-carbon list\n");
  117. X            return -1;
  118. X            }
  119. X        when 'c':
  120. X            if (argv[1]) {
  121. X            n = 0, addcc = *++argv;
  122. X            fix_up_addr(addcc);
  123. X            } else {
  124. X            print("Must specify carbon-copy list\n");
  125. X            return -1;
  126. X            }
  127. X        when 's':
  128. X            if (argv[1])
  129. X            n = 0, subj = *++argv;
  130. X            else
  131. X            n++, turnon(flgs, NEW_SUBJECT);
  132. X        when 'i': case 'h': case 'f': {
  133. X            int m;
  134. X            if (!msg_cnt) {
  135. X            print("No message to include!\n");
  136. X            return -1;
  137. X            }
  138. X            if (argv[0][n] == 'i') {
  139. X            turnon(flgs, INCLUDE);
  140. X            turnoff(flgs, INCLUDE_H);
  141. X            turnoff(flgs, FORWARD);
  142. X            } else if (argv[0][n] == 'h') {
  143. X            turnon(flgs, INCLUDE_H);
  144. X            turnoff(flgs, INCLUDE);
  145. X            turnoff(flgs, FORWARD);
  146. X            } else if (argv[0][n] == 'f') {
  147. X            turnon(flgs, FORWARD);
  148. X            turnoff(flgs, INCLUDE_H);
  149. X            turnoff(flgs, INCLUDE);
  150. X            }
  151. X            /* "-i 3-5" or "-i3-5"  Consider the latter case first */
  152. X            if (!argv[0][++n])
  153. X            argv++, n = 0;
  154. X            (*argv) += n;
  155. X            m = get_msg_list(argv, inc_list);
  156. X            (*argv) -= n;
  157. X            if (m == -1)
  158. X            return -1;
  159. X            /* if there were args, then go back to the first char
  160. X             * in the next argv
  161. X             */
  162. X            if (m)
  163. X            n = 0;
  164. X            if (!n) /* n may be 0 from above! */
  165. X            argv += (m-1);
  166. X        }
  167. X        when 'r':
  168. X            if (lower(firstchar) == 'r') {
  169. X            route = *++argv;
  170. X            n = 0;
  171. X            break;
  172. X            }
  173. X            /* fall thru */
  174. X        default:
  175. X            if (argv[0][n] != '?')
  176. X            wprint("%c: unknown option\n", argv[0][n]);
  177. X            wprint("available options\n");
  178. X#ifdef VERBOSE_ARG
  179. X            wprint("v      verbose (passed to mail delivery system)\n");
  180. X#endif /* VERBOSE_ARG */
  181. X            wprint("e      immediately enter editor (autoedit)\n");
  182. X            wprint("F      add fortune to the end of message.\n");
  183. X            wprint("s [subject]  prompt for or set subject.\n");
  184. X            wprint("c cc-addrs   set carbon-copy recipients.\n");
  185. X            wprint("b bcc-addrs  set blind-carbon-copy recipients.\n");
  186. X            wprint("i [msg#'s]   include msg_list into letter.\n");
  187. X            wprint("h [msg#'s]   include msg_list with headers.\n");
  188. X            wprint("f [msg#'s]   forward msg_list (not indented).\n");
  189. X            return -1;
  190. X        }
  191. X    }
  192. X    *in_reply_to = *To = *Subject = *Cc = *Bcc = 0;
  193. X    if (lower(firstchar) == 'r') {
  194. X    char *old_fmt = hdr_format, *pcc = NULL;
  195. X    to = To, cc = Cc;
  196. X    /*
  197. X     * Generate a reply to all the messages passed to respond().  This
  198. X     * list is different than the include-msg list above.  Get info about
  199. X     * whom the messages were sent to for reply-all.
  200. X     * BUG: currently, redundant addresses aren't pruned from Bcc list!
  201. X     */
  202. X    for (n = 0; n < msg_cnt; n++)
  203. X        if (msg_bit(list, n)) {
  204. X        if (to != To)
  205. X            *to++ = ',', *to++ = ' ';
  206. X        (void) reply_to(n, (firstchar == 'R'), buf);
  207. X        if (strlen(buf) + (to - To) > sizeof(To) - 1) {
  208. X            print("# recipients exceeded at msg %d\n", n);
  209. X            break;
  210. X        }
  211. X        to += Strcpy(to, buf);
  212. X        if (firstchar == 'R') {
  213. X            if (pcc) /* if there was a previous cc, append ", " */
  214. X            *cc++ = ',', *cc++ = ' ';
  215. X            if (pcc = cc_to(n, buf))
  216. X            if (strlen(pcc) + (cc - Cc) > sizeof(Cc) - 1)
  217. X                print("# Cc's exceeded at msg %d\n", n);
  218. X            else
  219. X                cc += Strcpy(cc, pcc);
  220. X        }
  221. X        /* remove redundant addresses now, or headers could get too
  222. X         * long before the list runs out (it still might)
  223. X         */
  224. X        rm_redundant_addrs(To, Cc);
  225. X        to = To + strlen(To);
  226. X        cc = Cc + strlen(Cc);
  227. X        }
  228. X    /* clean up end of Cc line for replyall's */
  229. X    while (*cc == ' ' || *cc == ',')
  230. X        *cc-- = '\0';
  231. X    to = To, cc = Cc;
  232. X    if (route || (route = do_set(set_options, "auto_route")))
  233. X        /* careful! This routine could add lots-o-bytes and lose addresses
  234. X         * to avoid writing out of segment.
  235. X         */
  236. X        route_addresses(To, Cc, route);
  237. X    if (hdr_format = do_set(set_options, "in_reply_to"))
  238. X        /* "9" here is a magic # --see compose_hdr() */
  239. X        (void) strcpy(in_reply_to, compose_hdr(current_msg)+9);
  240. X    hdr_format = old_fmt;
  241. X    }
  242. X    if (ison(flgs, FORWARD) && ison(flgs, EDIT) ||
  243. X        lower(firstchar) == 'r' && isoff(flgs, NEW_SUBJECT)) {
  244. X    turnoff(flgs, NEW_SUBJECT);
  245. X    if (subj = subject_to(current_msg, buf))
  246. X        subj = strcpy(Subject, buf + 4*(lower(firstchar) != 'r'));
  247. X    } else if (isoff(flgs, NEW_SUBJECT) && isoff(flgs, FORWARD) &&
  248. X    (do_set(set_options, "ask") || do_set(set_options, "asksub")))
  249. X    turnon(flgs, NEW_SUBJECT);
  250. X    if (argv && *argv) {
  251. X    char buf[HDRSIZ];
  252. X    (void) argv_to_string(buf, argv);
  253. X    fix_up_addr(buf);
  254. X    to = &To[strlen(To)];
  255. X    if (*To)
  256. X        *to++ = ',', *to++ = ' ';
  257. X    (void) strcpy(to, buf);
  258. X    to = To;
  259. X    }
  260. X    if (addcc && *addcc) {
  261. X    cc = &Cc[strlen(Cc)];
  262. X    if (*Cc)
  263. X        *cc++ = ',', *cc++ = ' ';
  264. X    (void) strcpy(cc, addcc); /* addcc has already been fixed up */
  265. X    cc = Cc;
  266. X    }
  267. X    /* remove any redundant addresses that just got added */
  268. X    rm_redundant_addrs(To, Cc);
  269. X    if (bcc && *bcc)
  270. X    (void) strncpy(Bcc, bcc, sizeof(Bcc)); /* bcc already fixed up */
  271. X    bcc = Bcc;
  272. X    if (do_set(set_options, "fortune"))
  273. X    turnon(flgs, DO_FORTUNE);
  274. X#ifdef SUNTOOL
  275. X    if (istool) {
  276. X    do_clear();
  277. X    panel_set(abort_item,   PANEL_SHOW_ITEM, TRUE,  0);
  278. X    panel_set(comp_item,    PANEL_SHOW_ITEM, FALSE, 0);
  279. X    panel_set(read_item,    PANEL_SHOW_ITEM, FALSE, 0);
  280. X    panel_set(respond_item, PANEL_SHOW_ITEM, FALSE, 0);
  281. X    }
  282. X#endif /* SUNTOOL */
  283. X    return mail_someone(to, subj, cc, bcc, flgs, inc_list);
  284. X}
  285. X
  286. X#ifdef SUNTOOL
  287. X/* panel item selection -- it's here because of local (static) variables */
  288. Xabort_mail(item, value)
  289. XPanel_item item;
  290. X{
  291. X    get_hdr_field = 0;
  292. X    if (item == abort_item && value != 2) {
  293. X    print("Aborted letter.");
  294. X    killme = 1, rm_edfile(SIGINT);
  295. X    flags = 0;
  296. X    }
  297. X    panel_set(comp_item,    PANEL_SHOW_ITEM, TRUE,  0);
  298. X    panel_set(send_item,    PANEL_SHOW_ITEM, FALSE, 0);
  299. X    panel_set(edit_item,    PANEL_SHOW_ITEM, FALSE, 0);
  300. X    panel_set(abort_item,   PANEL_SHOW_ITEM, FALSE, 0);
  301. X    panel_set(read_item,    PANEL_SHOW_ITEM, TRUE,  0);
  302. X    panel_set(respond_item, PANEL_SHOW_ITEM, TRUE,  0);
  303. X    turnoff(glob_flags, IS_GETTING);
  304. X    unlock_cursors();
  305. X}
  306. X#endif /* SUNTOOL */
  307. X
  308. Xmail_someone(to, subject, cc, bcc, flgs, list)
  309. Xregister char *to, *subject, *cc, *bcc, *list;
  310. Xu_long flgs;
  311. X{
  312. X    register char *p;
  313. X
  314. X    flags = flgs;
  315. X#ifdef SUNTOOL
  316. X    if (istool)
  317. X    rite(_tty.sg_kill), do_clear();
  318. X#endif /* SUNTOOL */
  319. X    if (to && *to) {
  320. X    if (!*To)
  321. X        (void) strncpy(To, to, sizeof(To));
  322. X    if (istool)
  323. X        wprint("To: %s\n", To);
  324. X    } else
  325. X#ifdef SUNTOOL
  326. X    if (istool)
  327. X        turnon(get_hdr_field, TO_FIELD);
  328. X    else
  329. X#endif /* SUNTOOL */
  330. X        to = NO_STRING;
  331. X    if (subject && *subject) {
  332. X    if (!*Subject)
  333. X        (void) strncpy(Subject, subject, sizeof(Subject));
  334. X    if (istool)
  335. X        wprint("Subject: %s\n", Subject);
  336. X    } else
  337. X#ifdef SUNTOOL
  338. X    if (istool && !*Subject && ison(flags, NEW_SUBJECT))
  339. X        turnon(get_hdr_field, SUBJECT);
  340. X    else
  341. X#endif /* SUNTOOL */
  342. X        subject = NO_STRING;
  343. X    if (cc && *cc) {
  344. X    if (!*Cc)
  345. X        (void) strncpy(Cc, cc, sizeof(Cc));
  346. X    if (istool)
  347. X        wprint("Cc: %s\n", Cc);
  348. X    } else
  349. X#ifdef SUNTOOL  /* get_hdr_field -- prevents prompting on reply and forward */
  350. X    if (istool && get_hdr_field && do_set(set_options, "askcc"))
  351. X        turnon(get_hdr_field, CC_FIELD);
  352. X    else
  353. X#endif /* SUNTOOL */
  354. X        Cc[0] = '\0';
  355. X    if (bcc && *bcc) {
  356. X    if (!*Bcc)
  357. X        (void) strncpy(Bcc, bcc, sizeof(Bcc));
  358. X    if (istool)
  359. X        wprint("Bcc: %s\n", Bcc);
  360. X    } else
  361. X#ifdef SUNTOOL  /* get_hdr_field -- prevents prompting on reply and forward */
  362. X    if (istool && get_hdr_field)
  363. X        turnon(get_hdr_field, BC_FIELD);
  364. X    else
  365. X#endif /* SUNTOOL */
  366. X        Bcc[0] = '\0';
  367. X
  368. X    if (ison(glob_flags, REDIRECT)) {
  369. X    send_it(); /* doesn't return */
  370. X    return 0;
  371. X    }
  372. X    /* if (!*to) then prompting will be done */
  373. X    if (!istool) {
  374. X    if (!(p = set_header("To: ", to, !*to)) || !*p) {
  375. X        puts("No recipients, can't mail.");
  376. X        return -1;
  377. X    }
  378. X    if (!*to) /* if user typed To-line here, fix up the address line */
  379. X        fix_up_addr(p);
  380. X    (void) strcpy(To, p);
  381. X    /* don't prompt for subject if forwarding mail */
  382. X    if (isoff(flags, FORWARD) && 
  383. X        (p = set_header("Subject: ", subject,
  384. X            !*subject && ison(flags, NEW_SUBJECT))))
  385. X        (void) strcpy(Subject, p);
  386. X    if (*Cc)
  387. X        printf("Cc: %s\n", Cc);
  388. X    if (*Bcc)
  389. X        printf("Bcc: %s\n", Bcc);
  390. X    putchar('\n');
  391. X    }
  392. X#ifdef SUNTOOL
  393. X    else if (!get_hdr_field) {
  394. X    panel_set(send_item, PANEL_SHOW_ITEM, TRUE, 0);
  395. X    panel_set(edit_item, PANEL_SHOW_ITEM, TRUE, 0);
  396. X    } else if (ison(flags, FORWARD) && ison(flags, EDIT) &&
  397. X        ison(get_hdr_field, TO_FIELD)) {
  398. X    print("Specify recipient(s) to forward in tool mode.\n");
  399. X    return -1;
  400. X    }
  401. X#endif /* SUNTOOL */
  402. X    /* If forwarding w/o editing, start a new file for each */
  403. X    if (ison(flags, FORWARD) && isoff(flags, EDIT)) {
  404. X    char fwd[MAXMSGS_BITS];
  405. X    register int i;
  406. X    clear_msg_list(fwd);
  407. X    for (i = 0; i < msg_cnt; i++)
  408. X        if (msg_bit(list, i)) {
  409. X        set_msg_bit(fwd, i);
  410. X        if (start_file(fwd) < 0)
  411. X            return -1;
  412. X        clear_msg_list(fwd);
  413. X        }
  414. X    } else
  415. X    return start_file(list);
  416. X}
  417. X
  418. Xstart_file(list)
  419. Xchar *list;
  420. X{
  421. X    register char  *dir;
  422. X    register int   i;
  423. X    char         line[MAXPATHLEN];
  424. X
  425. X    if (!(dir = do_set(set_options, "tmpdir")) &&
  426. X    !(dir = do_set(set_options, "home")))
  427. Xalted:
  428. X    dir = ALTERNATE_HOME;
  429. X    (void) mktemp(sprintf(line, "%s/%s", dir, EDFILE));
  430. X    strdup(edfile, line);
  431. X    if (!(ed_fp = mask_fopen(edfile, "w+"))) {
  432. X    if (strcmp(dir, ALTERNATE_HOME))
  433. X        goto alted;
  434. X#ifdef SUNTOOL
  435. X    if (istool)
  436. X        abort_mail(NO_ITEM, 0);
  437. X#endif /* SUNTOOL */
  438. X    error("can't create %s", edfile);
  439. X    return -1;
  440. X    }
  441. X    if (!istool) {
  442. X    oldint = signal(SIGINT, rm_edfile);
  443. X    oldquit = signal(SIGQUIT, rm_edfile);
  444. X    oldterm = signal(SIGTERM, rm_edfile);
  445. X    }
  446. X
  447. X    /* if flags call for it, include current message (with header?) */
  448. X    if (ison(flags, INCLUDE) || ison(flags,FORWARD) || ison(flags,INCLUDE_H)) {
  449. X    long copy_flgs = 0, is_forw = ison(flags, FORWARD);
  450. X    char buf[sizeof(To)];
  451. X    if (is_forw)
  452. X        turnon(copy_flgs, FORWARD);
  453. X    else
  454. X        turnon(copy_flgs, INDENT);
  455. X    if (ison(flags, INCLUDE))
  456. X        turnon(copy_flgs, NO_HEADER);
  457. X    if (ison(flags, INCLUDE) || is_forw)
  458. X        turnon(copy_flgs, NO_IGNORE);
  459. X#ifdef MMDF
  460. X    turnon(copy_flgs, NO_SEPARATOR);
  461. X#endif /* MMDF */
  462. X#ifdef SUNTOOL
  463. X    if (istool)
  464. X        lock_cursors();
  465. X#endif /* SUNTOOL */
  466. X    for (i = 0; i < msg_cnt; i++)
  467. X        if (msg_bit(list, i)) {
  468. X        if (is_forw && ison(flags, EDIT)) {
  469. X            (void) reply_to(i, FALSE, buf);
  470. X            fprintf(ed_fp, "--- Forwarded mail from %s\n\n", buf);
  471. X        }
  472. X        wprint("%sing message %d ...",
  473. X            is_forw? "forward" : "includ", i+1);
  474. X        wprint("(%d lines)\n", copy_msg(i, ed_fp, copy_flgs));
  475. X        set_isread(i); /* if we included it, we read it, right? */
  476. X        if (is_forw && ison(flags, EDIT))
  477. X            fprintf(ed_fp,
  478. X            "\n--- End of forwarded message from %s\n", buf);
  479. X        }
  480. X    fflush(ed_fp);
  481. X#ifdef SUNTOOL
  482. X    if (istool)
  483. X        unlock_cursors();
  484. X#endif /* SUNTOOL */
  485. X    }
  486. X    if (ison(glob_flags, WARNING)) {
  487. X    if (escape && !strncmp(escape, DEF_ESCAPE, 1))
  488. X        wprint("(escape character is set to `%c')\n", *escape);
  489. X    if (wrapcolumn && wrapcolumn < 20)
  490. X        wprint("(warning: wrapping only %d columns from the left!)\n",
  491. X            wrapcolumn);
  492. X    }
  493. X    turnon(glob_flags, IS_GETTING);
  494. X    /* enter editor if autoedit and not toolmode */
  495. X    if (
  496. X#ifdef SUNTOOL
  497. X        (!istool || !get_hdr_field) &&
  498. X#endif /* SUNTOOL */
  499. X    /* do an "if" again in case editor not found and EDIT turned off */
  500. X                    ison(flags, EDIT)) {
  501. X    char *argv[3];
  502. X    if (!(argv[0] = do_set(set_options, "visual")) || !*argv[0])
  503. X        argv[0] = DEF_EDITOR;
  504. X    argv[1] = edfile;
  505. X    argv[2] = NULL;
  506. X    print("Starting \"%s\"...\n", argv[0]);
  507. X    fclose(ed_fp);
  508. X    ed_fp = NULL_FILE;
  509. X    execute(argv);
  510. X    turnoff(flags, EDIT);
  511. X    turnoff(flags, FORWARD); /* forwarded messages must be unedited */
  512. X    /* upon exit of editor, user must now type ^D or "." to send */
  513. X    if (istool)
  514. X        return 0;
  515. X    if (!(ed_fp = fopen(edfile, "r+"))) {
  516. X        error("can't reopen %s", edfile);
  517. X        return -1;
  518. X    }
  519. X    (void) fseek(ed_fp, 0L, 2);
  520. X    puts("continue editing letter or ^D to send");
  521. X    } else if (ison(flags, FORWARD) &&
  522. X#ifdef SUNTOOL
  523. X           (!istool || !get_hdr_field) &&
  524. X#endif /* SUNTOOL */
  525. X           finish_up_letter())
  526. X    return 0; /* if forwarding mail, check to see if tool requires To: */
  527. X#ifdef SUNTOOL
  528. X    if (istool) {
  529. X    /* If toolmode, we're ready for IO. Give first prompt if not given */
  530. X    if (ison(get_hdr_field, TO_FIELD))
  531. X        wprint("To: ");
  532. X    else if (ison(get_hdr_field, SUBJECT))
  533. X        wprint("Subject: ");
  534. X    else if (ison(get_hdr_field, CC_FIELD))
  535. X        wprint("Cc: ");
  536. X    type_cursor(PIX_SRC);
  537. X    win_setcursor(msg_sw->ts_windowfd, &write_cursor);
  538. X    return 0;
  539. X    }
  540. X#endif /* SUNTOOL */
  541. X    i = 0;
  542. X    do  {
  543. X    /* If the user hits ^C in cbreak mode, mush will return to
  544. X     * Getstr and not clear the buffer. whatever is typed next will
  545. X     * be appended to the line.  jumping here will force the line to
  546. X     * be cleared cuz it's a new call.
  547. X     */
  548. X    (void) setjmp(cntrl_c_buf);
  549. X    while (Getstr(line, sizeof(line), 0) > -1) {
  550. X        if (!istool) /* toolmode checks on a timer -- don't do it here */
  551. X        (void) check_new_mail(); /* if new mail comes in, get it */
  552. X        if ((i = add_to_letter(line)) <= 0)
  553. X        break;
  554. X    }
  555. X    } while (i >= 0 && !finish_up_letter());
  556. X    return i; /* return -1 if ~x or ~q to terminate letter */
  557. X}
  558. X
  559. Xchar *tilde_commands[] = {
  560. X    "commands: [OPTIONAL argument]",
  561. X    "e [editor]\tEnter editor. Editor used: \"set editor\", env EDITOR, vi",
  562. X    "v [editor]\tEnter visual editor. \"set visual\", env VISUAL, vi",
  563. X    "p [pager]\tPage message; pager used: \"set pager\", env. PAGER, more",
  564. X    "i [msg#'s]\tInclude current msg body [msg#'s] indented by \"indent_str\"",
  565. X    "H [msg#'s]\tSame, but include the message headers from included messages",
  566. X    "f [msg#'s]\tForward mail. Not indented, but marked as \"forwarded mail\"",
  567. X    "t [list]\tChange list of recipients",
  568. X    "s [subject]\tModify [set] subject header",
  569. X    "c [cc list]\tModify [set] carbon copy recipients",
  570. X    "b [bcc list]\tModify [set] blind carbon recipients",
  571. X    "h\t\tModify all message headers",
  572. X    "S[!]\t\tInclude Signature file [suppress file]",
  573. X    "F[!]\t\tAdd a fortune at end of letter [don't add]",
  574. X    "w file\t\tWrite msg buffer to file name",
  575. X    "a file\t\tAppend msg buffer to file name",
  576. X    "r file\t\tRead filename into message buffer",
  577. X    "q \t\tQuit message; save in dead.letter (unless \"nosave\" is set).",
  578. X    "x \t\tQuit message; don't save in dead.letter.",
  579. X    "$variable\tInsert the string value for \"variable\" into message.",
  580. X    ":cmd\t\tRun the mail command \"cmd\".",
  581. X    "u\t\tedit previous line in file.",
  582. X    "E[!]\t\tClear contents of letter after saving to dead.letter [unless !].",
  583. X    0
  584. X};
  585. X
  586. X/*
  587. X * Add the line (char *) parameter to the letter.  Determine tilde
  588. X * escapes and determine what to do.  This function returns 0 to
  589. X * indicate user wants to end the letter, -1 if the letter cannot
  590. X * be sent (~q, ~x no buffer after editor, etc...) or 1 to indicate
  591. X * successful addition of the line to the letter.
  592. X */
  593. Xadd_to_letter(line)
  594. Xchar line[];
  595. X{
  596. X    register char *p;
  597. X    char buf[BUFSIZ];
  598. X
  599. X    killme = 0;
  600. X    (void) fseek(ed_fp, 0L, 2);
  601. X#ifdef SUNTOOL
  602. X    if (get_hdr_field) {
  603. X    /* These are received in order by design! */
  604. X    if (ison(get_hdr_field, TO_FIELD)) {
  605. X        if (!line[0]) {
  606. X            wprint("There must be a recipient!\nTo: ");
  607. X        return 1;
  608. X        }
  609. X        fix_up_addr(line);
  610. X        (void) strcpy(To, line), turnoff(get_hdr_field, TO_FIELD);
  611. X    } else if (ison(get_hdr_field, SUBJECT)) {
  612. X        (void) strcpy(Subject, line);
  613. X        turnoff(get_hdr_field, SUBJECT);
  614. X    } else if (ison(get_hdr_field, CC_FIELD)) {
  615. X        fix_up_addr(line);
  616. X        (void) strcpy(Cc, line);
  617. X        turnoff(get_hdr_field, CC_FIELD);
  618. X    } else if (ison(get_hdr_field, BC_FIELD)) {
  619. X        fix_up_addr(line);
  620. X        (void) strcpy(Bcc, line);
  621. X        turnoff(get_hdr_field, BC_FIELD);
  622. X    }
  623. X
  624. X        if (ison(get_hdr_field, SUBJECT))
  625. X        (void) set_header("Subject: ", Subject, 1);
  626. X        else if (ison(get_hdr_field, CC_FIELD))
  627. X        (void) set_header("Cc: ", Cc, 1);
  628. X        else if (ison(get_hdr_field, BC_FIELD))
  629. X        (void) set_header("Bcc: ", Bcc, 1);
  630. X    panel_set(send_item, PANEL_SHOW_ITEM, (get_hdr_field==0), 0);
  631. X    panel_set(edit_item, PANEL_SHOW_ITEM, (get_hdr_field==0), 0);
  632. X    if (!get_hdr_field) {
  633. X        wprint("\n");
  634. X        if (ison(flags, EDIT)) {
  635. X        (void) add_to_letter(sprintf(line, "%cv", *escape));
  636. X        turnoff(flags, EDIT);
  637. X        }
  638. X    }
  639. X    return 1;
  640. X    }
  641. X#endif /* SUNTOOL */
  642. X    if (!strcmp(line, ".") && (istool || do_set(set_options, "dot")))
  643. X    return 0;
  644. X    if (line[0] != *escape) {
  645. X    fputs(line, ed_fp), fputc('\n', ed_fp), fflush(ed_fp);
  646. X    return 1;
  647. X    }
  648. X    /* all commands are "~c" (where 'c' is the command). set p = first
  649. X     * character after 'c' and skip whitespace
  650. X     */
  651. X    p = &line[2];
  652. X    skipspaces(0);
  653. X    switch (line[1]) {
  654. X    case 'v' : case 'p': case 'e': {
  655. X        if (!*p || *p == 'i' && !p[1])
  656. X        switch (line[1]) {
  657. X            case 'p' :
  658. X            if (!*p && !(p = do_set(set_options, "pager")))
  659. X                p = DEF_PAGER;
  660. X            if (!*p || !strcmp(p, "internal"))
  661. X                p = NULL;
  662. X            when 'v' :
  663. X            if (p = do_set(set_options, "visual"))
  664. X                break;
  665. X            default :
  666. X            if (!(p = do_set(set_options, "editor")) || !*p)
  667. X                p = DEF_EDITOR;
  668. X        }
  669. X        if (line[1] == 'p') {
  670. X        rewind(ed_fp);
  671. X        (void) do_pager(p, TRUE); /* start the pager "p" */
  672. X        do_pager(sprintf(buf, "To: %s\n", To), FALSE);
  673. X        if (Subject[0])
  674. X            do_pager(sprintf(buf, "Subject: %s\n", Subject), FALSE);
  675. X        if (Cc[0])
  676. X            do_pager(sprintf(buf, "Cc: %s\n", Cc), FALSE);
  677. X        if (Bcc[0])
  678. X            do_pager(sprintf(buf, "Bcc: %s\n", Bcc), FALSE);
  679. X        do_pager(strcpy(buf, "--------\nMessage contains:\n"), FALSE);
  680. X        while (fgets(buf, sizeof(buf), ed_fp))
  681. X            if (do_pager(buf, FALSE) == EOF)
  682. X            break;
  683. X        (void) do_pager(NULL, FALSE); /* end pager */
  684. X        } else {
  685. X        char *argv[3];
  686. X        argv[0] = p;
  687. X        argv[1] = edfile;
  688. X        argv[2] = NULL;
  689. X        fclose(ed_fp);
  690. X        ed_fp = NULL_FILE;
  691. X        execute(argv); /* tool will return even tho editor isn't done */
  692. X        if (istool)
  693. X            return 1;
  694. X        if (!(ed_fp = fopen(edfile, "r+"))) {
  695. X            error("can't reopen %s", edfile);
  696. X            return -1;
  697. X        }
  698. X        }
  699. X    }
  700. X    when '$': {
  701. X        register char *p2;
  702. X        if (!(p2 = do_set(set_options, p)))
  703. X        wprint("(%s isn't set)\n", p);
  704. X        else
  705. X        putstring(p2, ed_fp);
  706. X    }
  707. X    when ':': {
  708. X        char new[MAXMSGS_BITS];
  709. X        u_long save_flags = glob_flags;
  710. X
  711. X        turnon(glob_flags, IGN_SIGS);
  712. X        turnon(glob_flags, IGN_BANG);
  713. X        turnoff(glob_flags, DO_PIPE);
  714. X        turnoff(glob_flags, IS_PIPE);
  715. X        (void) cmd_line(p, new);
  716. X        glob_flags = save_flags;
  717. X#ifdef SUNTOOL
  718. X        if (istool && msg_pix) /* the command was to read a message */
  719. X        return 1;
  720. X#endif /* SUNTOOL */
  721. X    }
  722. X    when 'i': case 'f': case 'H': case 'm': {
  723. X        int  n;
  724. X        long copy_flgs = 0;
  725. X        char list[MAXMSGS_BITS];
  726. X
  727. X        if (!msg_cnt) {
  728. X        print("No messages.\n");
  729. X        break;
  730. X        }
  731. X        clear_msg_list(list);
  732. X        if (line[1] != 'f')
  733. X        turnon(copy_flgs, INDENT);
  734. X        if (line[1] == 'i')
  735. X        turnon(copy_flgs, NO_HEADER);
  736. X#ifdef MMDF
  737. X        turnon(copy_flgs, NO_SEPARATOR);
  738. X#endif /* MMDF */
  739. X        if (!*p)
  740. X        set_msg_bit(list, current_msg);
  741. X        else if (!do_range(p, list))
  742. X        return 1;
  743. X#ifdef SUNTOOL
  744. X        if (istool)
  745. X        lock_cursors();
  746. X#endif /* SUNTOOL */
  747. X        for (n = 0; n < msg_cnt; n++)
  748. X        if (msg_bit(list, n)) {
  749. X            if (line[1] == 'f') {
  750. X            (void) reply_to(n, FALSE, buf);
  751. X            fprintf(ed_fp, "--- Forwarded mail from %s\n\n", buf);
  752. X            }
  753. X            wprint("Including message %d ... ", n+1);
  754. X            wprint("(%d lines)\n", copy_msg(n, ed_fp, copy_flgs));
  755. X            set_isread(n);
  756. X            if (line[1] == 'f')
  757. X        fprintf(ed_fp,"\n--- End of forwarded message from %s\n\n",buf);
  758. X        }
  759. X#ifdef SUNTOOL
  760. X        if (istool)
  761. X        unlock_cursors();
  762. X#endif /* SUNTOOL */
  763. X    }
  764. X    /* To: Cc: and Bcc: headers */
  765. X    when 'b':
  766. X    case 't':
  767. X    case 'c': {
  768. X        char *h = (line[1] == 't')? To : (line[1] == 'c')? Cc : Bcc;
  769. X        char *Prompt = line[1] == 't'? "To: " :
  770. X               line[1] == 'c'? "Cc: " : "Bcc: ";
  771. X#ifdef SUNTOOL
  772. X        if (!*p && istool) {
  773. X        turnon(get_hdr_field, CC_FIELD);
  774. X        (void) set_header(Prompt, h, 1);
  775. X        panel_set(send_item, PANEL_SHOW_ITEM, FALSE, 0);
  776. X        panel_set(edit_item, PANEL_SHOW_ITEM, FALSE, 0);
  777. X        return 1;
  778. X        }
  779. X#endif /* SUNTOOL */
  780. X        if (*p) {
  781. X        fix_up_addr(p);
  782. X        if (*h)
  783. X            (void) sprintf(h+strlen(h), ", %s", p);
  784. X        else
  785. X            (void) strcpy(h, p);
  786. X        } else if (!(p = set_header(Prompt, h, TRUE)) || !*p)
  787. X        if (line[1] == 't') {
  788. X            wprint("There must be a recipient!\n");
  789. X#ifdef SUNTOOL
  790. X            turnoff(get_hdr_field, TO_FIELD);
  791. X            panel_set(send_item, PANEL_SHOW_ITEM, TRUE, 0);
  792. X            panel_set(edit_item, PANEL_SHOW_ITEM, TRUE, 0);
  793. X#endif /* SUNTOOL */
  794. X        } else
  795. X            *h = 0;
  796. X        else {
  797. X        fix_up_addr(p);
  798. X        (void) strcpy(h, p);
  799. X        }
  800. X    }
  801. X    when 's':
  802. X#ifdef SUNTOOL
  803. X        if (!*p && istool) {
  804. X        turnon(get_hdr_field, SUBJECT);
  805. X        panel_set(send_item, PANEL_SHOW_ITEM, FALSE, 0);
  806. X        panel_set(edit_item, PANEL_SHOW_ITEM, FALSE, 0);
  807. X        (void) set_header("Subject: ", Subject, 1);
  808. X        return 1;
  809. X        }
  810. X#endif /* SUNTOOL */
  811. X        if (*p || (p = set_header("Subject: ", Subject, 1)))
  812. X        if (!*p)
  813. X            Subject[0] = 0;
  814. X        else
  815. X            (void) strcpy(Subject, p);
  816. X    when 'h':
  817. X#ifdef SUNTOOL
  818. X        if (istool) {
  819. X        turnon(get_hdr_field, TO_FIELD);
  820. X        turnon(get_hdr_field, SUBJECT);
  821. X        turnon(get_hdr_field, CC_FIELD);
  822. X        turnon(get_hdr_field, BC_FIELD);
  823. X        (void) set_header("To: ", To, 1);
  824. X        panel_set(send_item, PANEL_SHOW_ITEM, FALSE, 0);
  825. X        panel_set(edit_item, PANEL_SHOW_ITEM, FALSE, 0);
  826. X        return 1;
  827. X        }
  828. X#endif /* SUNTOOL */
  829. X        while ((p = set_header("To: ", To, 1)) && !*p)
  830. X        wprint("(There must be a recipient.)\n");
  831. X        (void) strcpy(To, p);
  832. X        if (p = set_header("Subject: ", Subject, 1))
  833. X        if (!*p)
  834. X            Subject[0] = 0;
  835. X        else
  836. X            (void) strcpy(Subject, p);
  837. X        if (p = set_header("Cc: ", Cc, 1))
  838. X        if (!*p)
  839. X            Cc[0] = 0;
  840. X        else {
  841. X            fix_up_addr(p);
  842. X            (void) strcpy(Cc, p);
  843. X        }
  844. X        if (p = set_header("Bcc: ", Bcc, 1))
  845. X        if (!*p)
  846. X            Bcc[0] = 0;
  847. X        else {
  848. X            fix_up_addr(p);
  849. X            (void) strcpy(Bcc, p);
  850. X        }
  851. X    when 'S':
  852. X        if (*p == '!')
  853. X        turnoff(flags, SIGN), wprint("not ");
  854. X        else
  855. X        turnon(flags, SIGN);
  856. X        wprint("adding signature file at end of message.\n");
  857. X    when 'F':
  858. X        if (*p == '!')
  859. X        turnoff(flags, DO_FORTUNE), wprint("not ");
  860. X        else
  861. X        turnon(flags, DO_FORTUNE);
  862. X        wprint("adding fortune at end of message.\n");
  863. X    when 'w': case 'a': case 'r':
  864. X        if (!*p) {
  865. X        wprint("(you must specify a filename)\n");
  866. X        return 1;
  867. X        }
  868. X        (void) fseek(ed_fp, 0L, 2); /* append */
  869. X        file_to_fp(p, ed_fp, (line[1] == 'r')? "r":
  870. X                  (line[1] == 'w')? "w": "a");
  871. X    /* go up one line in the message file and allow the user to edit it */
  872. X    when 'u': {
  873. X        long newpos, pos = ftell(ed_fp);
  874. X        char oldline[256];
  875. X        if (istool) {
  876. X        wprint("(Not available in tool mode.)\n");
  877. X        return 1;
  878. X        }
  879. X        if (pos <= 0L) { /* pos could be -1 if ftell() failed */
  880. X        wprint("(No previous line in file.)\n");
  881. X        return 1;
  882. X        }
  883. X        /* get the last 256 bytes written and read backwards from the
  884. X         * current place until '\n' is found. Start by moving past the
  885. X         * first \n which is at the end of the line we want to edit
  886. X         */
  887. X        newpos = max(0, pos - 256L);
  888. X        (void) fseek(ed_fp, newpos, L_SET);
  889. X        /* don't fgets -- it'll stop at a \n */
  890. X        (void) fread(line, sizeof(char), (int)(pos-newpos), ed_fp);
  891. X        pos--;
  892. X        /* the last char in line should be a \n cuz it was last input */
  893. X        if (line[(int)(pos-newpos)] != '\n')
  894. X        wprint("I don't know how, but your last line ended with %c.\n",
  895. X            line[(int)(pos-newpos)]);
  896. X        else
  897. X        line[(int)(pos-newpos)] = 0; /* null terminate \n for ^H-ing */
  898. X        for (pos--; pos > newpos && line[(int)(pos-newpos)] != '\n'; pos--)
  899. X        ;
  900. X        /* we've gone back to the end of the second previous line. Check
  901. X         * to see if the char we're pointing to is a \n.  It should be, but
  902. X         * if it's not, we moved back to the first line of the file.
  903. X         */
  904. X        if (line[(int)(pos-newpos)] == '\n')
  905. X        ++pos;
  906. X        /* save the old line that's there in case the user boo-boos */
  907. X        (void) strcpy(oldline, &line[(int)(pos-newpos)]);
  908. X        /* let set header print out the line and get the input */
  909. X        if (!(p = set_header("", &line[(int)(pos-newpos)], TRUE))) {
  910. X        wprint("Something bad happened and I don't know what it is.\n");
  911. X        p = oldline;
  912. X        } else if (*p == *escape)
  913. X        wprint("(Warning: %c escapes ignored on %cu lines.)\n",
  914. X                *escape, *escape);
  915. X        /* seek to to the position where the new line will go */
  916. X        (void) fseek(ed_fp, pos, L_SET);
  917. X        /* put the newly typed line */
  918. X        (void) fputs(p, ed_fp); /* don't add \n. padding may be necessary */
  919. X        /* if the new line is less than the old line, we're going to do
  920. X         * one of two things.  The best thing to do is to truncate the
  921. X         * file to the end of the new line.  Sys-v can't do that, so we
  922. X         * pad the line with blanks.  May be messy in some cases, but...
  923. X         */
  924. X        if ((pos = strlen(p) - strlen(oldline)) < 0) {
  925. X#ifndef SYSV
  926. X        /* add the \n, flush the file, truncate to the current pos */
  927. X        fputc('\n', ed_fp), fflush(ed_fp);
  928. X        (void) ftruncate(fileno(ed_fp), (int)ftell(ed_fp));
  929. X#else
  930. X        /* pad with blanks to the length of the old line. add \n */
  931. X        while (pos++ < 0)
  932. X            fputc(' ', ed_fp);
  933. X        fputc('\n', ed_fp), fflush(ed_fp);
  934. X#endif /* SYSV */
  935. X        } else
  936. X        /* the new line is >= the old line, add \n -- no trunc req. */
  937. X            fputc('\n', ed_fp);
  938. X        return 1;
  939. X     }
  940. X    /* break;  not here cuz of "return" (lint). */
  941. X    case 'E':
  942. X        if (*p != '!' && !do_set(set_options, "nosave"))
  943. X        dead_letter();
  944. X        if (emptyfile(&ed_fp, edfile) == -1)
  945. X        error(edfile);
  946. X        else
  947. X        wprint("Message buffer empty\n");
  948. X    when 'q':
  949. X        /* save in dead.letter if nosave not set -- rm_edfile(-2). */
  950. X        rm_edfile(-2); /* doesn't return out of tool mode */
  951. X        return -1;
  952. X        /* break; not stated cuz of "return" (lint) */
  953. X    case 'x':
  954. X        /* don't save dead.letter -- simulate normal rm_edfile() call */
  955. X        rm_edfile(0);
  956. X#ifdef SUNTOOL
  957. X        if (istool) {
  958. X        wprint("*Letter aborted*");
  959. X        type_cursor(PIX_CLR);
  960. X        }
  961. X#endif /* SUNTOOL */
  962. X        return -1;
  963. X        /* break; (not specified for lint) */
  964. X    default:
  965. X        if (line[1] == *escape) {
  966. X        fputs(&line[1], ed_fp), fputc('\n', ed_fp), fflush(ed_fp);
  967. X        return 1;
  968. X        } else if (line[1] == '?') {
  969. X        register int x;
  970. X        if (!istool)
  971. X            (void) do_pager(NULL, TRUE); /* start pager */
  972. X        for (x = 0; tilde_commands[x]; x++) {
  973. X            (void) sprintf(buf, "%s%s\n", escape, tilde_commands[x]);
  974. X            if (!istool) {
  975. X            if (do_pager(buf, FALSE))
  976. X                break;
  977. X            } else
  978. X            wprint(buf);
  979. X        }
  980. X        (void) sprintf(buf, "%s%s\t\tbegin a line with a single %s\n",
  981. X            escape, escape, escape);
  982. X        if (istool)
  983. X            wprint(buf);
  984. X        else {
  985. X            if (tilde_commands[x] == NULL)
  986. X            (void) do_pager(buf, FALSE);
  987. X            (void) do_pager(NULL, FALSE); /* end pager */
  988. X        }
  989. X#ifdef SUNTOOL
  990. X        if (istool)
  991. X            (void) help(0, "compose", tool_help);
  992. X#endif /* SUNTOOL */
  993. X        } else
  994. X        wprint("`%c': unknown %c escape. Use %c? for help.\n",
  995. X            line[1], *escape, *escape);
  996. X    }
  997. X    (void) fseek(ed_fp, 0L, 2); /* seek to end of file in case there's more */
  998. X    wprint("(continue editing letter)\n");
  999. X    return 1;
  1000. X}
  1001. X
  1002. X/*
  1003. X * finish up the letter. ask for the cc line, if verify is set, ask to
  1004. X * verify sending, continue editing, or to dump the whole idea.
  1005. X * Then check for signature and fortune.  Finally, pass it to send_it()
  1006. X * to actually send it off.
  1007. X */
  1008. Xfinish_up_letter()
  1009. X{
  1010. X    register char *p;
  1011. X    int c;
  1012. X    char buf[MAXPATHLEN];
  1013. X
  1014. X    /* forwarded mail has no additional personalized text */
  1015. X    if (ison(flags, FORWARD)) {
  1016. X    send_it();
  1017. X    turnoff(glob_flags, IS_GETTING);
  1018. X    return 1;
  1019. X    }
  1020. X
  1021. X    if (isoff(glob_flags, REDIRECT)) {
  1022. X    if (!istool) {
  1023. X        if (do_set(set_options, "askcc")) {
  1024. X        if (p = set_header("Cc: ", Cc, 1))
  1025. X            (void) strcpy(Cc, p);
  1026. X        }
  1027. X#ifdef MMDF
  1028. X        /* Give some sort of indication that the end was seen */
  1029. X        else
  1030. X        wprint("EOT\n");
  1031. X#endif /* MMDF */
  1032. X    }
  1033. X    /* ~v on the Cc line asks for verification, first initialize p! */
  1034. X    p = NULL;
  1035. X    if (!strncmp(Cc, "~v", 2) || (p = do_set(set_options, "verify"))) {
  1036. X        if (!p) /* so we don't Cc to ~v! */
  1037. X        *Cc = 0;
  1038. X        for (;;) {
  1039. X#ifdef SUNTOOL
  1040. X        if (istool) {
  1041. X            type_cursor(PIX_CLR);
  1042. X            print("Send, Continue, Discard [Left, Middle, Right]?");
  1043. X            c = confirm(msg_sw->ts_windowfd);
  1044. X            clr_bot_line(); /* really: clears print window */
  1045. X            if (isascii(c))
  1046. X            Lower(c);
  1047. X            else switch(c) {
  1048. X            when MS_LEFT : c = 's';
  1049. X            when MS_MIDDLE : c = 'c';
  1050. X            when MS_RIGHT : c = 'd';
  1051. X            otherwise: c = 0;
  1052. X            }
  1053. X        } else
  1054. X#endif /* SUNTOOL */
  1055. X        {
  1056. X            print("send, continue editing, discard [s,c,d]? ");
  1057. X            c = Getstr(buf, sizeof(buf), 0);
  1058. X        }
  1059. X        if (c < 0)
  1060. X            putchar('\n');
  1061. X        else if (!istool)
  1062. X            c = lower(*buf);
  1063. X        if (c == 'd') {
  1064. X            rm_edfile(-2);
  1065. X            return 1;
  1066. X        } else if (c == 'c') {
  1067. X            wprint("(continue editing letter)\n");
  1068. X#ifdef SUNTOOL
  1069. X            if (istool)
  1070. X            type_cursor(PIX_SRC);
  1071. X#endif /* SUNTOOL */
  1072. X            return 0;
  1073. X        } else if (c == 's')
  1074. X            break;
  1075. X        }
  1076. X    }
  1077. X    }
  1078. X
  1079. X#ifdef SUNTOOL
  1080. X    if (istool)
  1081. X    lock_cursors();
  1082. X#endif /* SUNTOOL */
  1083. X    send_it();
  1084. X    turnoff(glob_flags, IS_GETTING);
  1085. X    return 1;
  1086. X}
  1087. X
  1088. X/*
  1089. X * actually send the letter.
  1090. X * 1. reset all the signals because of fork.
  1091. X * 2. determine recipients (users, address, files, programs)
  1092. X * 3. determine mailer, fork and return (if not verbose).
  1093. X * 4. popen mailer, $record, and other files specified in step 1.
  1094. X * 5. make the headers; this includes To: line, and user set headers, etc...
  1095. X * 6. copy the letter right into the array of file pointers (step 1).
  1096. X * 7. close the mailer and other files (step 1) and remove the edit-file.
  1097. X */
  1098. Xstatic void
  1099. Xsend_it()
  1100. X{
  1101. X    register char *p, *b, *addr_list;
  1102. X#ifdef MAXFILES
  1103. X    register int size = MAXFILES - 1;
  1104. X    FILE *files[MAXFILES];
  1105. X#else
  1106. X    register int size = getdtablesize() - 1;
  1107. X    FILE *files[30];  /* 30 should be sufficiently large enough */
  1108. X#endif /* MAXFILES */
  1109. X    int next_file = 1; /* reserve files[0] for the mail delivery program */
  1110. X    int log_file = -1; /* the index into the files array for mail logging */
  1111. X    char buf[3*HDRSIZ];
  1112. X    char expand = !do_set(set_options, "no_expand");
  1113. X    int fork_err = 0;
  1114. X
  1115. X    if (!istool) {
  1116. X    (void) signal(SIGINT, oldint);
  1117. X    (void) signal(SIGQUIT, oldquit);
  1118. X    (void) signal(SIGTERM, oldterm);
  1119. X    }
  1120. X
  1121. X    if (!(p = do_set(set_options, "sendmail")))
  1122. X    p = MAIL_DELIVERY;
  1123. X
  1124. X#ifdef VERBOSE_ARG
  1125. X    if (ison(flags, VERBOSE) || do_set(set_options, "verbose"))
  1126. X#ifdef MMDF
  1127. X    b = &buf[strlen(sprintf(buf, "%s%s", p, VERBOSE_ARG))];
  1128. X#else /* MMDF */
  1129. X    b = &buf[strlen(sprintf(buf, "%s %s", p, VERBOSE_ARG))];
  1130. X#endif /* MMDF */
  1131. X    else
  1132. X#endif /* VERBOSE_ARG */
  1133. X    b = buf + Strcpy(buf, p);
  1134. X#ifdef METOO_ARG
  1135. X    if (!strcmp(p, MAIL_DELIVERY) && do_set(set_options, "metoo"))
  1136. X    b += strlen(sprintf(b, " %s", METOO_ARG));
  1137. X#endif /* METOO_ARG */
  1138. X    *b++ = ' ', *b = 0; /* strcat(b, " "); */
  1139. X    addr_list = b; /* save this position to check for addresses later */
  1140. X
  1141. X    /*
  1142. X     * Build the address lines to give to the mail transfer system.  This
  1143. X     * address line cannot contain comment fields!  First, expand aliases
  1144. X     * since they may contain comment fields within addresses. Copy this
  1145. X     * result back into the Buffer since this will go into the header ...
  1146. X     * Next, remove all comments so the buffer contains ONLY valid addresses.
  1147. X     * Next, strip off any filenames/programs which might occur in the list.
  1148. X     * Finally, add this information to the command line buffer (buf).
  1149. X     * Remove commas if necessary (see ifdefs).  In the event of errors,
  1150. X     * force a dead letter by rm_edfile(-1).
  1151. X     */
  1152. X    if (!(p = alias_to_address(To))) {
  1153. X    print("address expansion failed for To: line.\n");
  1154. X    rm_edfile(-1);
  1155. X    } else {
  1156. X    next_file += find_files(p, files+next_file, size - next_file);
  1157. X    if (expand)
  1158. X        (void) strcpy(To, p);
  1159. X    rm_cmts_in_addr(p);
  1160. X    skipspaces(0);
  1161. X    if (!*p) {
  1162. X        print("There must be at least 1 legal recipient on the To line\n");
  1163. X        while (--next_file > 0)
  1164. X        fclose(files[next_file]);
  1165. X        rm_edfile(-2);
  1166. X        return;
  1167. X    }
  1168. X    b += Strcpy(b, p);
  1169. X    }
  1170. X    if (*Cc) {
  1171. X    if (!(p = alias_to_address(Cc))) {
  1172. X        print("address expansion failed for Cc: line.\n");
  1173. X        while (--next_file > 0)
  1174. X        fclose(files[next_file]);
  1175. X        rm_edfile(-1);
  1176. X    } else {
  1177. X        next_file += find_files(p, files+next_file, size - next_file);
  1178. X        if (expand)
  1179. X        (void) strcpy(Cc, p);
  1180. X        rm_cmts_in_addr(p);
  1181. X        skipspaces(0);
  1182. X        if (*p) {
  1183. X        *b++ = ',', *b++ = ' ';
  1184. X        b += Strcpy(b, p);
  1185. X        }
  1186. X    }
  1187. X    }
  1188. X
  1189. X    /* Sign the letter before adding the Bcc list since they aren't
  1190. X     * considered when adding a signature.
  1191. X     */
  1192. X    if ((ison(flags, SIGN) || ison(flags, DO_FORTUNE)) &&
  1193. X    isoff(glob_flags, REDIRECT) && isoff(flags, FORWARD))
  1194. X    sign_letter(addr_list, flags, ed_fp);
  1195. X
  1196. X    if (*Bcc) {
  1197. X    if (!(p = alias_to_address(Bcc))) {
  1198. X        print("address expansion failed for Bcc: line.\n");
  1199. X        while (--next_file > 0)
  1200. X        fclose(files[next_file]);
  1201. X        rm_edfile(-1);
  1202. X    } else {
  1203. X        next_file += find_files(p, files+next_file, size - next_file);
  1204. X        (void) strcpy(Bcc, p);
  1205. X        rm_cmts_in_addr(p);
  1206. X        skipspaces(0);
  1207. X        if (*p) {
  1208. X        *b++ = ',', *b++ = ' ';
  1209. X        b += Strcpy(b, p);
  1210. X        }
  1211. X    }
  1212. X    }
  1213. X
  1214. X#ifdef NO_COMMAS
  1215. X    for (p = buf; p = index(p, ','); p++)
  1216. X    *p = ' ';
  1217. X#endif /* NO_COMMAS */
  1218. X
  1219. X    Debug("mail command: %s\n", buf);
  1220. X
  1221. X#ifdef SUNTOOL
  1222. X    if (istool)
  1223. X    abort_mail(NO_ITEM, 0);
  1224. X#endif /* SUNTOOL */
  1225. X
  1226. X    if (isoff(flags, VERBOSE) && debug < 3)
  1227. X    switch (fork()) {
  1228. X        case  0:  /* the child will send the letter. ignore signals */
  1229. X#ifdef SYSV
  1230. X        if (setpgrp() == -1)
  1231. X            error("setpgrp");
  1232. X#endif /* SYSV */
  1233. X#ifdef MMDF
  1234. X        (void) signal(SIGCHLD, SIG_DFL);
  1235. X#endif /* MMDF */
  1236. X        (void) signal(SIGINT, SIG_IGN);
  1237. X        (void) signal(SIGHUP, SIG_IGN);
  1238. X        (void) signal(SIGQUIT, SIG_IGN);
  1239. X        (void) signal(SIGTERM, SIG_IGN);
  1240. X#ifdef SIGTTIN
  1241. X        (void) signal(SIGTTOU, SIG_IGN);
  1242. X        (void) signal(SIGTTIN, SIG_IGN);
  1243. X#endif /* SIGTTIN */
  1244. X#ifdef SIGCONT
  1245. X        (void) signal(SIGCONT, SIG_IGN);
  1246. X        (void) signal(SIGTSTP, SIG_IGN);
  1247. X#endif /* SIGCONT */
  1248. X        turnon(glob_flags, IGN_SIGS);
  1249. X        when -1:
  1250. X        error("fork failed trying to send mail");
  1251. X        fork_err++;
  1252. X        rm_edfile(-1);
  1253. X        /* fall thru */
  1254. X        default:
  1255. X        if (!fork_err && isoff(glob_flags, REDIRECT))
  1256. X            fclose(ed_fp);
  1257. X#ifdef SUNTOOL
  1258. X                if (istool) {
  1259. X            if (!fork_err) {
  1260. X            wprint("Letter sent.");
  1261. X            print("Letter sent.");
  1262. X            }
  1263. X            type_cursor(PIX_CLR);
  1264. X        }
  1265. X#endif /* SUNTOOL */
  1266. X        while (--next_file > 0)
  1267. X            fclose(files[next_file]);
  1268. X#ifdef MMDF
  1269. X        if (!fork_err)
  1270. X            (void) wait((int *) 0);
  1271. X#endif /* MMDF */
  1272. X        return;
  1273. X    }
  1274. X
  1275. X#ifdef MMDF
  1276. X    *(addr_list-1) = '\0';
  1277. X#endif /* MMDF */
  1278. X    if (debug > 2)
  1279. X    files[0] = stdout;
  1280. X    else if (!(files[0] = open_file(buf, TRUE))) {
  1281. X    rm_edfile(-1); /* force saving of undeliverable mail */
  1282. X    if (isoff(flags, VERBOSE) && debug < 3)
  1283. X        exit(-1);
  1284. X    else
  1285. X        return;
  1286. X    }
  1287. X
  1288. X    if (ison(flags, VERBOSE))
  1289. X    wprint("Sending letter ... "), fflush(stdout);
  1290. X#ifdef MMDF
  1291. X    /* give address list to submit */
  1292. X    for (p = addr_list; p && (p = any(p, ",<")); p++)
  1293. X    if (*p == ',')
  1294. X        *p = '\n';
  1295. X    else
  1296. X        p = index(p, '>');
  1297. X    fprintf(files[0], "%s\n\n", addr_list);
  1298. X#endif /* MMDF */
  1299. X
  1300. X    /* see if log is set.  This is just to add message headers. No msg body. */
  1301. X    if (p = do_set(set_options, "logfile")) {
  1302. X    if (!*p)
  1303. X        p = "~/mail.log";
  1304. X    (void) strcpy(buf, p);
  1305. X    log_file = next_file;
  1306. X    next_file += find_files(buf, files+next_file, size - next_file);
  1307. X    if (log_file == next_file)
  1308. X        log_file = -1;
  1309. X    }
  1310. X
  1311. X    /* see if record is set.  If so, open that file for appending and add
  1312. X     * the letter in a format such that mail can be read from it
  1313. X     */
  1314. X    if (p = do_set(set_options, "record")) {
  1315. X    if (!*p)
  1316. X        p = "~/record";
  1317. X    (void) strcpy(buf, p);
  1318. X    next_file += find_files(buf, files+next_file, size - next_file);
  1319. X    }
  1320. X
  1321. X    /* Make folders conform to RFC-822 by adding From: and Date: headers.
  1322. X     * Some older mailers (binmail, execmail, delivermail), don't add
  1323. X     * these headers, so add them for #define OLD_MAILER.  Also add them
  1324. X     * with the "Resent-" prefix when forwarding.
  1325. X     */
  1326. X    {
  1327. X    time_t t;
  1328. X    char From_buf[256], *pF = From_buf, date_str[64];
  1329. X    char *host = NULL;
  1330. X    
  1331. X    if (ourname)
  1332. X        host = ourname[0];
  1333. X
  1334. X    if (ison(flags, FORWARD))
  1335. X        pF += Strcpy(From_buf, "Resent-");
  1336. X    pF += Strcpy(pF, "From: ");
  1337. X#ifdef UUCP
  1338. X    if (host && *host)
  1339. X        pF += strlen(sprintf(pF, "%s!", host));
  1340. X#endif /* UUCP */
  1341. X    pF += Strcpy(pF, login);
  1342. X#ifndef UUCP
  1343. X    if (host && *host)
  1344. X        pF += strlen(sprintf(pF, "@%s", host));
  1345. X#endif /* UUCP */
  1346. X    if (p = do_set(set_options, "realname"))
  1347. X        pF += strlen(sprintf(pF, " (%s)", p));
  1348. X    *pF++ = '\n', *pF++ = 0;
  1349. X    (void) time(&t);
  1350. X    for (size = 0; size < next_file; size++) {
  1351. X#ifndef OLD_MAILER
  1352. X        if (size == 0 && isoff(flags, FORWARD))
  1353. X        continue;
  1354. X#endif /* OLD_MAILER */
  1355. X        if (size > 0) {
  1356. X#ifndef MSG_SEPARATOR
  1357. X        fprintf(files[size], "From %s %s", login, ctime(&t));
  1358. X#else /* MSG_SEPARATOR */
  1359. X#ifdef MMDF
  1360. X        fputs(MSG_SEPARATOR, files[size]);
  1361. X#else /* MMDF */
  1362. X        fprintf(files[size], "%s\n", MSG_SEPARATOR);
  1363. X#endif /* MMDF */
  1364. X#endif /* MSG_SEPARATOR */
  1365. X        }
  1366. X        fputs(From_buf, files[size]);
  1367. X        fprintf(files[size], "%sDate: %s\n",
  1368. X        ison(flags, FORWARD) ? "Resent-" : "", rfc_date(date_str));
  1369. X    }
  1370. X    }
  1371. X
  1372. X    /* first print users own message headers */
  1373. X    if (own_hdrs && !do_set(set_options, "no_hdrs")) {
  1374. X    struct options *opts;
  1375. X    for (opts = own_hdrs; opts; opts = opts->next)
  1376. X        for (size = 0; size < next_file; size++)
  1377. X        fprintf(files[size], "%s %s\n", opts->option, opts->value);
  1378. X    }
  1379. X
  1380. X    wrap_addrs(To, 80);
  1381. X    wrap_addrs(Cc, 80);
  1382. X    wrap_addrs(Bcc, 80);
  1383. X    /* send the header stuff to sendmail and end header with a blank line */
  1384. X    for (size = 0; size < next_file; size++) {
  1385. X    if (*in_reply_to)
  1386. X        fprintf(files[size], "In-Reply-To: %s\n", in_reply_to);
  1387. X    fprintf(files[size], "X-Mailer: %s\n", VERSION);
  1388. X    fprintf(files[size], "%sTo: %s\n",
  1389. X        ison(flags, FORWARD) ? "Resent-" : "", To);
  1390. X    if (*Subject && isoff(flags, FORWARD))
  1391. X        fprintf(files[size], "Subject: %s\n", Subject);
  1392. X    if (*Cc)
  1393. X        fprintf(files[size], "%sCc: %s\n",
  1394. X        ison(flags, FORWARD) ? "Resent-" : "", Cc);
  1395. X    if (size > 0) {
  1396. X        /* Do not send these to mail transfer agent */
  1397. X        if (*Bcc)
  1398. X        fprintf(files[size], "%sBcc: %s\n",
  1399. X        ison(flags, FORWARD) ? "Resent-" : "", Bcc);
  1400. X        fprintf(files[size], "Status: OR\n");
  1401. X    }
  1402. X    if (isoff(flags, FORWARD))
  1403. X        fputc('\n', files[size]);
  1404. X    }
  1405. X
  1406. X    /* if redirection, ed_fp = stdin, else rewind the file just made */
  1407. X    if (isoff(glob_flags, REDIRECT))
  1408. X    rewind(ed_fp);
  1409. X    else
  1410. X    ed_fp = stdin;
  1411. X
  1412. X    /* Read from stdin or the edfile till EOF and send it all to the mailer
  1413. X     * and other open files/folders/programs. Check for "From " at the
  1414. X     * beginnings of these lines to prevent creating new messages in folders.
  1415. X     * If forwarding, skip the leading From_ line of the forwarded message.
  1416. X     */
  1417. X#ifndef MSG_SEPARATOR
  1418. X    if (ison(flags, FORWARD) && fgets(buf, sizeof buf, ed_fp)) {
  1419. X    if (strncmp(buf, "From ", 5) != 0)
  1420. X        rewind(ed_fp); /* No From_ line (should never happen) */
  1421. X    }
  1422. X#endif /* !MSG_SEPARATOR */
  1423. X    while (fgets(buf, sizeof buf, ed_fp))
  1424. X    for (size = 0; size < next_file; size++) {
  1425. X        if (size == log_file)
  1426. X        continue;
  1427. X#ifndef MSG_SEPARATOR
  1428. X        if (!strncmp(buf, "From ", 5))
  1429. X        fputc('>', files[size]);
  1430. X#endif /* MSG_SEPARATOR */
  1431. X        fputs(buf, files[size]);
  1432. X    }
  1433. X
  1434. X    /* loop thru the open files (except for the first: the mail delivery agent)
  1435. X     * and append a blank line so that ucb-mail can read these folders.
  1436. X     * Then close the files.  If the file was a popened program, the sigchld
  1437. X     * that the program generates will close the file.
  1438. X     */
  1439. X#ifdef END_MSG_SEP
  1440. X    for (size = 1; size < next_file; size++) {
  1441. X    fputs(END_MSG_SEP, files[size]);
  1442. X    if (files[size])
  1443. X        fclose(files[size]);
  1444. X    }
  1445. X#else /* !END_MSG_SEP */
  1446. X    for (size = 1; size < next_file; size++)
  1447. X    if (files[size]) {
  1448. X        fputc('\n', files[size]);
  1449. X        fclose(files[size]);
  1450. X    }
  1451. X#endif /* END_MSG_SEP */
  1452. X
  1453. X#ifdef MMDF
  1454. X    if (debug < 3) {
  1455. X    int reply_code = pclose(files[0]);
  1456. X    Debug("pclose reply_code = %d\n", reply_code);
  1457. X    rm_edfile((reply_code >> 8) == 9 ? 0 : -1);
  1458. X    } else
  1459. X    rm_edfile(0);
  1460. X#else /* MMDF */
  1461. X    rm_edfile(0);
  1462. X    if (debug < 3)
  1463. X    (void) pclose(files[0]);
  1464. X#endif /* MMDF */
  1465. X
  1466. X    if ((ison(flags, VERBOSE) || debug > 2) && isoff(glob_flags, REDIRECT))
  1467. X    wprint("sent.\n");
  1468. X    else
  1469. X    exit(0); /* not a user exit -- a child exit */
  1470. X}
  1471. X
  1472. X/* ARGSUSED */
  1473. XSIGRET
  1474. Xrm_edfile(sig)
  1475. X{
  1476. X    if (sig > 0) {
  1477. X    /* wrapcolumn may have been trashed -- restore it */
  1478. X    char *fix = do_set(set_options, "wrapcolumn");
  1479. X    if (fix && *fix)
  1480. X        wrapcolumn = atoi(fix);
  1481. X    mac_flush(); /* abort pending macros */
  1482. X    }
  1483. X    /* now check whether we should abort the letter */
  1484. X    if (sig > 0 && !killme) {
  1485. X    if (!istool)
  1486. X        (void) signal(sig, rm_edfile);
  1487. X    killme = 1;
  1488. X    wprint("\n** interrupt -- one more to kill letter **\n");
  1489. X#ifdef SUNTOOL
  1490. X    if (istool) {
  1491. X        type_cursor(PIX_SRC);
  1492. X        return;
  1493. X    }
  1494. X#endif /* SUNTOOL */
  1495. X    longjmp(cntrl_c_buf, 1);
  1496. X    }
  1497. X    killme = 0;
  1498. X    /* if sig == -1, force a save into dead.letter.
  1499. X     * else, check for nosave not being set and save anyway if it's not set
  1500. X     * sig == 0 indicates normal exit (or ~x), so don't save a dead letter.
  1501. X     */
  1502. X    if (sig == -1 || sig != 0 && !do_set(set_options, "nosave"))
  1503. X    dead_letter();
  1504. X    if (isoff(glob_flags, REDIRECT))
  1505. X    fclose(ed_fp);
  1506. X    (void) unlink(edfile);
  1507. X
  1508. X    turnoff(glob_flags, IS_GETTING);
  1509. X    if (sig == -1)
  1510. X    return;
  1511. X#ifdef SUNTOOL
  1512. X    if (sig && istool > 1) {
  1513. X    wprint("*Letter aborted*");
  1514. X    abort_mail(abort_item, 2);
  1515. X    }
  1516. X#endif /* SUNTOOL */
  1517. X
  1518. X    if (sig == SIGHUP)
  1519. X    cleanup(0);
  1520. X    if (!istool) {
  1521. X    (void) signal(SIGINT, oldint);
  1522. X    (void) signal(SIGQUIT, oldquit);
  1523. X    (void) signal(SIGTERM, oldterm);
  1524. X    }
  1525. X
  1526. X    if (sig == 0)
  1527. X    return;
  1528. X    if (istool || sig == -2) /* make sure sigchld is reset first */
  1529. X    return;
  1530. X
  1531. X    if (isoff(glob_flags, DO_SHELL)) {  /* If we're not in a shell, exit */
  1532. X    puts("exiting");
  1533. X    echo_on();
  1534. X    exit(1);
  1535. X    }
  1536. X    longjmp(jmpbuf, 1);
  1537. X}
  1538. X
  1539. X/* save letter into dead letter */
  1540. Xdead_letter()
  1541. X{
  1542. X    char     *p, buf[BUFSIZ];
  1543. X    long     t;
  1544. X    FILE     *dead;
  1545. X
  1546. X    if (ison(glob_flags, REDIRECT)) {
  1547. X    print("input redirected -- can't save dead letter.\n");
  1548. X    return;
  1549. X    }
  1550. X    /* If the file doesn't exist, get outta here. File may not exist if
  1551. X     * user generated a ^C from a promptable header and catch sent us here.
  1552. X     */
  1553. X    if (Access(edfile, R_OK))
  1554. X    return;
  1555. X    /* User may have killed mush via a signal while he was in an editor.
  1556. X     * ed_fp will be NULL in this case.  Since the file does exist (above),
  1557. X     * open it so we can copy it to dead letter.
  1558. X     */
  1559. X    if (!ed_fp && !(ed_fp = fopen(edfile, "r"))) {
  1560. X    error("can't save dead letter from %s", edfile);
  1561. X    return;
  1562. X    }
  1563. X    /* don't save a dead letter if there's nothing to save. */
  1564. X    if (fseek(ed_fp, 0L, 2) || ftell(ed_fp) <= 1L)
  1565. X    return;
  1566. X    if (!(p = do_set(set_options, "dead")))
  1567. X    p = "~/dead.letter";
  1568. X    if (!(dead = open_file(p, FALSE)))
  1569. X    return;
  1570. X    (void) time (&t);
  1571. X    fflush(ed_fp);
  1572. X    rewind(ed_fp);
  1573. X#ifdef MSG_SEPARATOR
  1574. X    fputs(MSG_SEPARATOR, dead);
  1575. X#else /* MSG_SEPARATOR */
  1576. X    fprintf(dead, "From %s %s", login, ctime(&t));
  1577. X#endif /* MSG_SEPARATOR */
  1578. X    fprintf(dead, "To: %s\nSubject: %s\n", To, Subject);
  1579. X    fprintf(dead, "Date: %s\n", rfc_date(buf));
  1580. X    if (*Cc)
  1581. X    fprintf(dead, "Cc: %s\n", Cc);
  1582. X    if (*Bcc)
  1583. X    fprintf(dead, "Bcc: %s\n", Bcc);
  1584. X    (void) fputc('\n', dead);
  1585. X    while (fgets(buf, sizeof(buf), ed_fp))
  1586. X    (void) fputs(buf, dead);
  1587. X    (void) fputc('\n', dead);
  1588. X#ifdef END_MSG_SEP
  1589. X    fputs(END_MSG_SEP, dead);
  1590. X#endif /* END_MSG_SEP */
  1591. X    (void) fclose(dead);
  1592. X    print("Saved unfinished letter in %s.\n", p);
  1593. X}
  1594. END_OF_FILE
  1595. if test 46580 -ne `wc -c <'mail.c'`; then
  1596.     echo shar: \"'mail.c'\" unpacked with wrong size!
  1597. fi
  1598. # end of 'mail.c'
  1599. fi
  1600. echo shar: End of archive 16 \(of 19\).
  1601. cp /dev/null ark16isdone
  1602. MISSING=""
  1603. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
  1604.     if test ! -f ark${I}isdone ; then
  1605.     MISSING="${MISSING} ${I}"
  1606.     fi
  1607. done
  1608. if test "${MISSING}" = "" ; then
  1609.     echo You have unpacked all 19 archives.
  1610.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1611. else
  1612.     echo You still need to unpack the following archives:
  1613.     echo "        " ${MISSING}
  1614. fi
  1615. ##  End of shell archive.
  1616. exit 0
  1617.